package fr.insalyon.sims.broadcast.service;

import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;

import fr.insalyon.sims.broadcast.image.ImageInputBuffer;
import fr.insalyon.sims.broadcast.network.DataErrorEvent;
import fr.insalyon.sims.broadcast.network.DataErrorListener;
import fr.insalyon.sims.broadcast.network.MCastStreamTransmitter;
import fr.insalyon.sims.broadcast.network.TCPStreamReceiver;
import fr.insalyon.sims.streamManagerClient.Response;
import fr.insalyon.sims.streamManagerClient.Service;

public class BroadcastTransmitterService extends BroadcastService implements DataErrorListener {
	// ------------------------------------------------------- CONSTANTS -- //
	// ------------------------------------------------------ ATTRIBUTES -- //
	
	// Input TCP/IP stream
	private TCPStreamReceiver receiver;
	
	// Output multicast stream
	private MCastStreamTransmitter transmitter;
	
	private int srcPort;
	
	private InetAddress multicastAddress;
	
	private int multicastPort;
	
	// ---------------------------------------------------- CONSTRUCTORS -- //
	
	/**
	 * Constructor
	 */
	public BroadcastTransmitterService (int srcPort,
			InetAddress multicastAdress, int multicastPort) {
		this.srcPort = srcPort;
		this.multicastAddress = multicastAdress;
		this.multicastPort = multicastPort;
	}
	
	// --------------------------------------------------------- METHODS -- //
	

	public synchronized Response doStart(HashMap<String, String> params) {
		// Create and connect multicast output stream
		try {
			transmitter = new MCastStreamTransmitter(
					multicastAddress, multicastPort);
			transmitter.connect();
		} catch (IOException e) {
			transmitter = null;
			return getErrorResponse(113,"Could not start multicast output " +
					"stream. Exception: " + e.getMessage());
		}
		
		// Create and connect TCP/IP input stream
		receiver = new TCPStreamReceiver(srcPort);
		receiver.connect();
		
		// Add listeners
		receiver.addDataErrorListener(this);
		receiver.addDataListener(new ImageInputBuffer(transmitter));
		transmitter.addDataErrorListener(this);
		
		// Starts daemons
		transmitter.start();
		receiver.start();
		
		return getSuccessResponse(srcPort);
	}

	public synchronized Response doStop() {
		if (this.receiver != null) {
			// Stop transmitter
			this.transmitter.stop();
			this.transmitter.disconnect();
			
			// Stop receiver
			this.receiver.stop();
			this.receiver.disconnect();
				
			this.receiver = null;
			this.transmitter = null;
		}
		
		return getSuccessResponse();
	}


	public String getName() {
		return "BroadcastTransmitterService";
	}


	public int getServiceType() {
		return Service.MULTICAST;
	}


	public void streamError(DataErrorEvent event) {
		// TODO throw to Stream Manager
		System.err.println("[" + getName() + "] An exception occured!");
		event.getException().printStackTrace();
		doStop();
	}
	
	// ------------------------------------------------- PRIVATE METHODS -- //
	// --------------------------------------------------- INNER CLASSES -- //

}